package com.jnpf.consumer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jnpf.flow.FlowUtil;
import com.rabbitmq.client.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
@Slf4j
@RequiredArgsConstructor
public abstract class FlowEventConsumer {


	@Value("${flow.event.queue:defaultQueue}")
	private String flowQueue;

	@Value("${flow.key}")
	private String key;

	@Bean
	public Queue queue() {
		return new Queue(flowQueue, true);
	}

	/**
	 * RabbitMQ 消息接收方法
	 * @param message 接收到的消息对象
	 */
	@RabbitListener(queues = "#{queue.name}", ackMode = "MANUAL")
	public void onMessage(FlowEventMessage message, Channel channel, Message amqpMessage) throws IOException {
		log.info("消息内容:{}", JSONObject.toJSONString(message));
		if ("defaultQueue".equals(flowQueue) || flowQueue == null) {
			log.warn("队列名称未配置或无效，将跳过消息处理。");
			return;
		}
		long deliveryTag = amqpMessage.getMessageProperties().getDeliveryTag();
		try {
			// 调用抽象方法处理具体事件
			processEvent(message);
			// 手动确认消息
			channel.basicAck(deliveryTag, false);
			log.info("[{}同步结束][处理结果({})]", message.getEventType(), JSON.toJSONString(message));
		} catch (Exception e) {
			log.warn("消息处理失败, {}", JSONObject.toJSONString(message), e);
			channel.basicNack(deliveryTag, false, false); // 重新入队，稍后重试
			handleProcessingError(message, e);
		}
	}


	/**
	 * 抽象方法，子类实现具体事件的处理逻辑
	 * @param message 事件内容
	 */
	protected abstract void processEvent(FlowEventMessage message);

	/**
	 * 处理消息消费过程中的异常
	 * @param message 处理异常的消息
	 * @param e 异常对象
	 */
	protected void handleProcessingError(FlowEventMessage message, Exception e) {
		// 默认异常处理，可以被子类重写
		// 默认调用企业微信消息通知
		FlowUtil.pushMessage(FlowUtil.buildErrorMessageTemplate("流程事件消费失败", EventTypeEnum.getDesc(message.getEventType()),
				key, e.getMessage(), message.getTaskId(), JSON.toJSONString(message)));
		log.error("流程事件消费失败,message={}", JSON.toJSONString(message), e);
	}
}
